package com.afdor.rws.event.driven.api;

import com.afdor.rws.annotation.extension.SPI;
import com.afdor.rws.core.Callback;
import com.afdor.rws.event.driven.api.channel.consumer.handler.EventHandler;
import com.afdor.rws.event.driven.api.channel.consumer.handler.EventRetryStrategy;
import com.afdor.rws.event.driven.config.EventBusConfig;
import com.afdor.rws.event.driven.config.EventConsumerConfig;
import com.afdor.rws.event.driven.config.EventProducerConfig;
import com.afdor.rws.event.driven.entities.Event;
import com.afdor.rws.event.driven.support.holder.EventResult;

import java.util.Arrays;
import java.util.List;

/**
 * 事件总线定义
 *
 * @author 悭梵
 * @date Created in 2018-08-14 10:22
 */
@SPI("default")
public interface EventBus {

    /**
     * 初始化
     *
     * @return
     */
    <T extends EventBus> T init();

    /**
     * 获取配置信息
     *
     * @return
     */
    <C extends EventBusConfig> C getConfig();

    /**
     * 这是配置信息
     *
     * @param config
     * @param <T>
     * @return
     */
    <T extends EventBus, C extends EventBusConfig> T setConfig(C config);

    /**
     * 获取事件持久化管理器
     *
     * @return
     */
    EventPersistenceManager getEventPersistenceManager();

    /**
     * 设置事件持久化管理器
     *
     * @return
     */
    <T extends EventBus> T setEventPersistenceManager(EventPersistenceManager eventPersistenceManager);


    /**
     * 获取事件状态变更管理器
     *
     * @return
     */
    EventChangeManager getEventStatusChangeManager();

    /**
     * 设置事件状态变更管理器
     *
     * @return
     */
    <T extends EventBus> T setEventStatusChangeManager(EventChangeManager eventStatusChangeManager);

    /**
     * 注册事件处理器
     *
     * @param eventHandler
     */
    default <T extends EventBus> T registerEventHandler(EventConsumerConfig eventConsumerConfig, EventHandler eventHandler) {
        return registerEventHandler(eventConsumerConfig, eventHandler, null);
    }

    /**
     * 注册事件处理器，并使用特定重试机制
     *
     * @param eventHandler
     * @param eventRetryStrategy
     * @param <T>
     * @return
     */
    <T extends EventBus> T registerEventHandler(EventConsumerConfig eventConsumerConfig, EventHandler eventHandler, EventRetryStrategy eventRetryStrategy);

    /**
     * 发布生成者
     *
     * @param eventProducerConfig
     * @param <T>
     * @return
     */
    <T extends EventBus> T publishEventProducer(EventProducerConfig eventProducerConfig);

    /**
     * 同步发送并提交事件消息
     *
     * @param event
     * @param <V>   返回结果对象
     * @return
     */
    <V> EventResult<V> sendEvent(Event event);

    /**
     * 发送异步消息并异步处理成功回调
     *
     * @param event
     * @return
     */
    <V> void asyncSendEvent(Event event, Callback<EventResult<V>, Void> callback);

    /**
     * 异步事件消息
     *
     * @param event
     * @return
     */
    void sendAsyncEvent(Event event);

    /**
     * 批量发送异步事件消息
     *
     * @param events
     * @return
     */
    default void batchSendAsyncEvent(Event... events) {
        if (events == null || events.length == 0) {
            return;
        }
        batchSendAsyncEvent(Arrays.asList(events));
    }

    /**
     * 批量发送异步事件消息
     *
     * @param eventList
     * @return
     */
    void batchSendAsyncEvent(List<Event> eventList);

    /**
     * 开启一个新事物，多次调用会返回多个不同的值
     *
     * @return 返回事物标识。为使用线程本地变量来存此标识，避免多线程切换带来的问题，可放心使用线程池
     */
    String newTransaction();

    /**
     * 添加到发送队列事件消息
     *
     * @param events
     * @param transactionId 事物标识
     */
    void addEvent(String transactionId, Event... events);

    /**
     * 将添加到队列中的事件统一提交
     *
     * @param transactionId 事物标识
     * @return
     */
    boolean commit(String transactionId);

    /**
     * 将添加到队列中的事件统一回滚
     *
     * @param transactionId 事物标识
     */
    void rollback(String transactionId);

    /**
     * 退出时关闭通道
     */
    void destroy();

}
